package com.dongbao.core.rules.xml;

import com.dongbao.core.base.CodeRulesCommonBase;
import com.dongbao.core.config.MyState;
import com.dongbao.core.rules.CodeRulesBase;
import com.dongbao.dialog.DHGToolWindow;
import com.dongbao.entity.AwardedInfo;
import com.dongbao.entity.DaoIsDelete;
import com.dongbao.util.StorageConfig;
import com.dongbao.util.ToolUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import org.jdom.*;
import org.jdom.input.SAXBuilder;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *  Sql不允许关联三张以上的表,将会影响查询效率
 * */
public class SqlIsDeleteRules extends CodeRulesCommonBase implements CodeRulesBase {

    private static final Logger LOGGER = Logger.getInstance(DHGToolWindow.class);

    public SqlIsDeleteRules(VirtualFile afterFile, PsiFile psiFile, Project project) {
        super(afterFile,psiFile,project);
        this.code = "未知";
        this.level = "未知";
    }

    /**
     * 执行规则判断
     * */
    @Override
    public void run(List<AwardedInfo> deduction) {
        /* 执行分析当前class是否负责当前规则 */
        try {
            printDeleteSql(deduction,afterFile.getPath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void printDeleteSql(List<AwardedInfo> deduction,String filepath) throws Exception{
        String namespace = "";//mybatis命名空间

        //创建一个解析器
        SAXBuilder builder = new SAXBuilder();

        //创建一个文件输入流
        InputStream in = new FileInputStream(filepath);

        //将流加载到解析器中。
        Document document = builder.build(in);

        //获取文档的根节点
        Element rootElement = document.getRootElement();

        List<Attribute> list0 = rootElement.getAttributes();
        for(Attribute attr : list0){
            if("namespace".equals(attr.getName())) {
                namespace = attr.getValue() + ".";
            }
        }
        //将根节点的所有子节点获取放到一个集合中
        List<Element> list = rootElement.getChildren();

        //循环遍历所有子节点
        for(Element element : list){
            String id = "";//sqlid
            String type = element.getName();//sql类型
            String content = element.getText();//sql内容
            //自行组装一个SQL语句,防止标签的问题损失语句
            content = "";
            List<Content> contents = element.getContent();
            for(Content contentsElt : contents){
                if(contentsElt instanceof Text){
                    content += ((Text)contentsElt).getText();
                }else if(contentsElt instanceof Element){
                    Element contentElement = (Element)contentsElt;
                    if(contentElement.getName().equals("include")){
                        content += "*";
                    }else if(contentElement.getName().equals("foreach")
                            && "(".equals(contentElement.getAttribute("open"))
                            && ")".equals(contentElement.getAttribute("close"))){
                        content += " (1) ";
                    }
                }else if(contentsElt instanceof CDATA){
                    content += ((CDATA)contentsElt).getText();
                }
            }


            if("select".equals(type)){
                //获取所有的属性,输出sqlid
                List<Attribute> list1 = element.getAttributes();
                for(Attribute attr : list1){
                    if("id".equals(attr.getName())) {
                        id = attr.getValue();
                    }
                }
                //将里面的所有子节点全部换成 1

                //将所有的 # 参数对象替换为空字符串
                String tempSql = content.toString().replaceAll("#\\{.*?\\}", "''").replaceAll("\\$\\{.*?\\}", "''").replaceAll("`", "");
                //SQL转换为对象
                Statement parse = null;
                try{
                    parse = CCJSqlParserUtil.parse(tempSql, ccjSqlParser -> ccjSqlParser.withSquareBracketQuotation(true));
                }catch (Exception e){
//                    throw e;

                }
                if(parse!=null && parse instanceof Select){
                    Select select = (Select)parse;
                    SelectBody selectBody = select.getSelectBody();
                    Map<String,List<String>> whereTableColum = new HashMap<String,List<String>>();
                    valiSqlBody(deduction,selectBody,whereTableColum);
                    LOGGER.info("666");
                    List<DaoIsDelete> startDaoIsDelete = ToolUtil.getStartDaoIsDelete();
                    for(DaoIsDelete daoIsDelete:startDaoIsDelete){
                        if(whereTableColum.containsKey(daoIsDelete.getTableCode())){
                            List<String> colums = whereTableColum.get(daoIsDelete.getTableCode());
                            if(!colums.contains("is_delete")){
//                                int endNumber = fileContent.indexOf(id);
//                                String substring = fileContent.substring(0, endNumber);
//                                int countLeng = substring.length();
//                                int rowNumber = countLeng - substring.replace("\\n","").length();
                                com.intellij.openapi.editor.Document psiDocument = PsiDocumentManager.getInstance(this.project).getDocument(this.psiFile);
                                int lineNumber = psiDocument.getLineNumber(psiDocument.getText().indexOf(id));

                                packDeduction(
                                        deduction,
                                        afterFile.getName(),
                                        afterFile.getPath(),
                                        id,
                                        "文件["+this.afterFile.getName()+"]中["+id+"]的查询语句中查询的表["+daoIsDelete.getTableCode()+"]未加is_delete条件,请添加is_delete条件。",lineNumber,lineNumber);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 解析 SQL主体对象
     * */
    private void valiSqlBody(List<AwardedInfo> deduction,SelectBody selectBody,Map<String,List<String>> whereTableColum){
        if(selectBody instanceof PlainSelect){
            PlainSelect plainSelect = (PlainSelect)selectBody;
            //获取Where进行判断
            Expression where = plainSelect.getWhere();
            valiWhere(deduction,where,whereTableColum,selectBody);
        }
    }

    /**
     * 解析验证Where 条件
     * */
    private void valiWhere(List<AwardedInfo> deduction,Expression where,Map<String,List<String>> whereTableColum,SelectBody selectBody){
        if(where instanceof AndExpression){
            AndExpression andExpression = (AndExpression)where;
            Expression leftExpression = andExpression.getLeftExpression();
            Expression rightExpression = andExpression.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);
        } else if(where instanceof InExpression){
            InExpression inExpression = (InExpression)where;
            Expression leftExpression = inExpression.getLeftExpression();
//            ItemsList rightItemsList = inExpression.getRightItemsList();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
//            valiWhere(deduction,rightExpression);
        } else if(where instanceof Column){
            Column column = (Column)where;
            Table table = column.getTable();
            String columnName = column.getColumnName();
            List<String> columnNames = null;
            String tableName = null;
            //获取表名是主表的还是关联表的
            if(table!=null && table.getName()!=null){
                //主表判断
                if(selectBody instanceof PlainSelect){
                    PlainSelect plainSelect = (PlainSelect)selectBody;
                    Table fromItem = (Table)plainSelect.getFromItem();
                    if(table.getName().equals(fromItem.getAlias().getName())){
                        //表名等于from表的别名,则设置为from的表code
                        tableName = fromItem.getFullyQualifiedName();
                    }else{
                        tableName = fromItem.getFullyQualifiedName();
                    }
                }
            }else{
                //没有写表名 或者 匿名表明的前缀,算在主表的
                try{
                    PlainSelect plainSelect = (PlainSelect)selectBody;
                    if(plainSelect.getFromItem() instanceof Table){
                        Table fromItem = (Table)plainSelect.getFromItem();
                        tableName = fromItem.getFullyQualifiedName();
                    }else if(plainSelect.getFromItem() instanceof SubSelect){
                        SubSelect fromItem = (SubSelect)plainSelect.getFromItem();
                        tableName = fromItem.getAlias().getName();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            if(whereTableColum.containsKey(tableName)){
                columnNames = whereTableColum.get(tableName);
            }else{
                columnNames = new ArrayList<String>();
            }
            columnNames.add(columnName);
            whereTableColum.put(tableName,columnNames);
        } else if(where instanceof Parenthesis){
            Parenthesis parenthesis = (Parenthesis)where;
            Expression expression = parenthesis.getExpression();
            valiWhere(deduction,expression,whereTableColum,selectBody);
        }else if(where instanceof OrExpression){
            OrExpression orExpression = (OrExpression)where;
            Expression leftExpression = orExpression.getLeftExpression();
            Expression rightExpression = orExpression.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);
        }else if(where instanceof EqualsTo){
            EqualsTo equalsTo = (EqualsTo)where;
            Expression leftExpression = equalsTo.getLeftExpression();
            Expression rightExpression = equalsTo.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);
        }else if(where instanceof MinorThanEquals) {
            //比较的字符串值对象,不需要做处理
            MinorThanEquals minorThanEquals = (MinorThanEquals)where;
            Expression leftExpression = minorThanEquals.getLeftExpression();
            Expression rightExpression = minorThanEquals.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);
        }else if(where instanceof GreaterThan){
            GreaterThan greaterThan = (GreaterThan)where;
            Expression leftExpression = greaterThan.getLeftExpression();
            Expression rightExpression = greaterThan.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);
        }else if(where instanceof NotEqualsTo){
            NotEqualsTo notEqualsTo = (NotEqualsTo)where;
            Expression leftExpression = notEqualsTo.getLeftExpression();
            Expression rightExpression = notEqualsTo.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);

        }else if(where instanceof IsNullExpression){
            //SQL函数 不做处理
            IsNullExpression isNullExpression = (IsNullExpression)where;
            Expression leftExpression = isNullExpression.getLeftExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);

        }else if(where instanceof SignedExpression){
            //SQL函数 不做处理
            SignedExpression signedExpression = (SignedExpression)where;
            valiWhere(deduction,signedExpression.getExpression(),whereTableColum,selectBody);
        }else if(where instanceof GreaterThanEquals){
            //SQL函数 不做处理
            GreaterThanEquals greaterThanEquals = (GreaterThanEquals)where;
            Expression leftExpression = greaterThanEquals.getLeftExpression();
            Expression rightExpression = greaterThanEquals.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);
        }else if(where instanceof SubSelect){
            //SQL函数 不做处理
            SubSelect subSelect = (SubSelect)where;
//            valiWhere(deduction,subSelect,whereTableColum,selectBody);
            valiSqlBody(deduction,subSelect.getSelectBody(),whereTableColum);
        }else if(where instanceof PlainSelect){
            //SQL函数 不做处理
            PlainSelect plainSelect = (PlainSelect)where;
            valiWhere(deduction,plainSelect.getWhere(),whereTableColum,plainSelect);

        }else if(where instanceof LikeExpression){
            //SQL函数 不做处理
            LikeExpression likeExpression = (LikeExpression)where;
            Expression leftExpression = likeExpression.getLeftExpression();
            Expression rightExpression = likeExpression.getRightExpression();
            valiWhere(deduction,leftExpression,whereTableColum,selectBody);
            valiWhere(deduction,rightExpression,whereTableColum,selectBody);

        }else if(where instanceof Subtraction){
            //SQL函数 不做处理

        }else if(where instanceof Function){
            //SQL函数 不做处理

        }else if(where instanceof StringValue){
            //比较的字符串值对象,不需要做处理

        }else if(where instanceof LongValue){
            //比较的字符串值对象,不需要做处理

        }else if(where==null){

        }else {
//            throw new RuntimeException("未设定当前类型对象的Where 验证条件");
        }
    }

    @Override
    public String describe() {
        return "验证MyBatis中SQL语句是否带了IsDelete";
    }
}
